/**************************************************************/
/*  This file is licensed from, and is a trade secret of:     */
/*                                                            */
/*    Mercury Computer Systems, Incorporated                  */
/*    199 Riverneck Road                                      */
/*    Chelmsford, Massachusetts 01824-2820                    */
/*    United States of America                                */
/*    Telephone + 1 978 256-1300                              */
/*                                                            */
/*  Refer to your Software License Agreement for provisions   */
/*  on use, duplication, or disclosure.                       */
/*  US. Government users and prime contractors are also       */
/*  governed by the following Data Rights Notice:             */
/*  Use, duplication or disclosure by the US. Government is   */
/*  subject to the provisions set forth in FAR 52.227-14 for  */
/*  restricted rights or other agency data rights provisions  */
/*  on commercial software and documentation, as applicable.  */
/*                                                            */
/*  This file: (a) was developed at private expense, and no   */
/*  part was developed with government funds, (b) is a        */
/*  trade secret of Mercury Computer Systems, Inc. for the    */
/*  purposes of the Freedom of Information Act, (c) is        */
/*  "commercial computer software" subject to limited         */
/*  utilization as provided in the above noted Software       */
/*  License Agreement and (d) is in all respects data         */
/*  belonging exclusively to Mercury Computer Systems, Inc..  */
/*                                                            */
/**************************************************************/

/******************************************************************/
/* Copyright (c) 1999-2003, Mercury Computer Systems, Inc.,       */
/* Chelmsford MA.,and all third party embedded software sources.  */
/* All rights reserved under the Copyright laws of US. and        */
/* international treaties.                                        */
/*                                                                */
/* Patent Pending                                                 */
/******************************************************************/


//$COPYRIGHT_END


#include <stdlib.h>
#include <stdio.h>
#include <string>
#include "mac_xmit.h"

extern "C" {
  MAC_EXPORT
  POA_CF::Resource *
  CreateMacXmit (const char * identifier)
  {
    MacXmit * encoder;

    if (MacXmit::Create (encoder, identifier) != success) {
      return 0;
    }

    return (POA_CF::Resource *) encoder;
  }
}

MacXmit::MacXmit (const char * identifier)
  : CF__Resource_impl (identifier),
    m_running (false),
    m_bStop (false),
    m_packets_received (0),
    m_previous_flow_ctrl_state (SDR_FM3TR::MAC_Signaling::NOOP),
    m_hop_rate (0.0),
    m_freq_hop_sub_band (SDR_FM3TR::HSB1),
    m_freq_hop_set (0.0),
    m_flow_control_on( false)
{
  // Define ports.
  m_mac_xmit_in = new MAC_SendFeedback_InPort_impl<MacXmit> (this);
  m_mac_err_out = 
    new MAC_Ctrl_OutPort_impl<SDR_FM3TR::MAC_Signaling::MAC_ErrorControl_XmitLocal> ();
  m_mac_flowctrl_out = 
    new MAC_Ctrl_OutPort_impl<SDR_FM3TR::MAC_Signaling::MAC_FlowControl_Local> ();
}

MacXmit::~MacXmit ()
{
  delete m_mac_xmit_in;
  delete m_mac_err_out;
  delete m_mac_flowctrl_out;
}

status
MacXmit::Create (MacXmit *& handle,
                 const char * identifier)
{
  MacXmit * Temp = new MacXmit (identifier);

  if (!Temp) {
    handle = 0;
    return fail;
  }

  handle = Temp;
  return success;
}

status
MacXmit::Init ()
{
#ifdef MCS_VERBOSE
  std::cout << "MacXmit: Initializing." << std::endl;
#endif

  return success;
}

void
MacXmit::start ()
  throw (CORBA::SystemException, CF::Resource::StartError)
{
  if (m_running) {
    return;
  }

  Init ();
  m_running = true;
  CF__Resource_impl::start ();
}

void
MacXmit::stop ()
  throw (CORBA::SystemException, CF::Resource::StopError)
{
  m_bStop = true;
}

CORBA::Object_ptr
MacXmit::getPort (const CORBA::Char * name)
  throw (CORBA::SystemException, CF::PortSupplier::UnknownPort)
{
  std::string temp (name);

  if (temp == "MAC_Feedback_Input") {
    return m_mac_xmit_in->getPort ();
  }
  else if (temp == "Mac_ErrCtrl_Output") {
    return m_mac_err_out->getPort ();
  }
  else if (temp == "MAC_FlowCtrl_Output") {
    return m_mac_flowctrl_out->getPort ();
  }
  else {
    throw CF::PortSupplier::UnknownPort ();
  }
}

void
MacXmit::SendFeedback (SDR_FM3TR::MAC_Signaling::MAC_Signal_Ack ack, 
		       SDR_FM3TR::MAC_Signaling::MAC_Signal_FlowControl fc)
  throw (CORBA::SystemException)
{
  SDR_FM3TR::MAC_Signaling::MAC_ErrorControl_XmitLocal_ptr remote_error_port;

  remote_error_port = m_mac_err_out->getRemotePort();

  if (m_mac_err_out->IsConnected()) {
    switch (ack) {
    case SDR_FM3TR::MAC_Signaling::ACK:
      // No need to send ACK, ACK by default.
      break;

    case SDR_FM3TR::MAC_Signaling::NAK:
      {
	/*
	 * An ack is received for every packet, so the ID of the 
	 * error packet is synthesized from counting the packets.
	 */

#ifdef MCS_VERBOSE
	std::cout << "MacXmit: Received NAK feedback; echoing NAK for packet "
		  << m_packets_received << std::endl;
#endif

	remote_error_port->signalNAK (m_packets_received);
      }
    break;

    default:
      assert (!"Unknown MAC ACK type received/decoded by MAC Xmit component");
    }
  }

  m_packets_received++;

  /*
   * For the flow control, we only signal the remote component if
   * the flow control state changes.
   */

  SDR_FM3TR::MAC_Signaling::MAC_FlowControl_Local_ptr remote_flow_port;

  remote_flow_port = m_mac_flowctrl_out->getRemotePort();

  if (m_mac_flowctrl_out->IsConnected()) {
    switch (fc) {
    case SDR_FM3TR::MAC_Signaling::LOW_WATERMARK:
      if (m_previous_flow_ctrl_state != SDR_FM3TR::MAC_Signaling::LOW_WATERMARK) {
#ifdef MCS_VERBOSE
	std::cout << "MacXmit: Received low watermark signal." << std::endl;
#endif
	remote_flow_port->signalLowWatermark ();
	m_previous_flow_ctrl_state = SDR_FM3TR::MAC_Signaling::LOW_WATERMARK;
      }
      break;

    case SDR_FM3TR::MAC_Signaling::HIGH_WATERMARK:
      if (m_previous_flow_ctrl_state != SDR_FM3TR::MAC_Signaling::HIGH_WATERMARK) {
#ifdef MCS_VERBOSE
	std::cout << "MacXmit: Received high watermark signal." << std::endl;
#endif
	remote_flow_port->signalHighWatermark ();
	m_previous_flow_ctrl_state = SDR_FM3TR::MAC_Signaling::HIGH_WATERMARK;
      }
      break;

    case SDR_FM3TR::MAC_Signaling::EMPTY:
      if (m_previous_flow_ctrl_state != SDR_FM3TR::MAC_Signaling::EMPTY) {
#ifdef MCS_VERBOSE
	std::cout << "MacXmit: Received empty signal." << std::endl;
#endif
	remote_flow_port->signalEmpty ();
	m_previous_flow_ctrl_state = SDR_FM3TR::MAC_Signaling::EMPTY;
      }
      break;

    case SDR_FM3TR::MAC_Signaling::NOOP:
      // Don't need to do anything for NOOP
      break;

    default:
      assert(!"Unknown MAC Flow Control type received/decoded by MAC Xmit component");
    }
  }
} // End of  MacXmit::SendFeedback()
